<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://cyan-blog.oss-cn-shenzhen.aliyuncs.com/cdn/js/three.min.js"></script>
  <style>
    * {
      margin: 0;
      padding: 0
    }

    #canvas {
      position: fixed;
      width: 100%;
      height: 100%;
      z-index: -999;
      /* background: linear-gradient(to right top, #009fff, #ec2f4b); */
      background: linear-gradient(to right bottom, #140a2d, #7d31d2);
      /* 背景相对于元素内容固定，元素变 背景变 */
      background-attachment: local;
      background-position: center;
      /* 图像不会被重复 (因为背景图像所在的区域将可能没有完全被覆盖). 没有被重复的背景图像的位置是由background-position属性来决定。 */
      background-repeat: no-repeat;
      animation: bganimation 10s infinite;
      background-size: 800%;
    }
    @keyframes bganimation{
      0%{
        background-position: 0 50%;
      }
      50%{
        background-position: 100% 50%;
      }
      100%{
        background-position: 0 50%;
      }
    }
  </style>
</head>

<body>
  <div id="canvas"></div>
  <script>
    var scene,//场景  
      camera,//摄像机
      renderer,//渲染

      container,//容器
      aspect,//摄像机视锥体长宽比
      fov,//。。。。。。垂直视野角度
      plane,//。。。。。。近端面
      far,//。。。。。。远端面

      mouseX,//鼠标位置
      mouseY,

      windowHalfX,//平面一半
      windowHalfY,
      geometry,
      starStuff,
      materialOptions,
      stars;

    init();
    animate();

    function init() {
      container = document.getElementById(`canvas`);

      mouseX = 0;
      mouseY = 0;

      aspect = window.innerWidth / window.innerHeight;
      fov = 40;
      plane = 1;
      far = 800;

      windowHalfX = window.innerWidth / 2;
      windowHalfY = window.innerHeight / 2;

      camera = new THREE.PerspectiveCamera(//确定视锥范围，在范围内才能被渲染
        fov,
        aspect,
        plane,
        far
      );

      camera.position.z = far / 2;

      scene = new THREE.Scene({ antialias: true });//抗锯齿
      scene.fog = new THREE.FogExp2(0x1b1b1b, 0.0001);//雾化效果

      starForge();

      renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
      renderer.setPixelRatio((window.devicePixelRatio) ? window.devicePixelRatio : 1);//设置设备像素比
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.autoClear = false;//re得到的像素数据叠加
      renderer.setClearColor(0x000000, 0.0);
      container.appendChild(renderer.domElement);

      document.addEventListener('mousemove', onMouseMove, false);
    }

    function animate() {//动画
      requestAnimationFrame(animate);
      render();
    }

    function render() {//渲染
      camera.position.x += (mouseX - camera.position.x) * 0.005;
      camera.position.y += (-mouseY - camera.position.y) * 0.005;
      camera.lookAt(scene.position);
      renderer.render(scene, camera);
    }

    function starForge() {
      var amount = 45000;
      geometry = new THREE.SphereGeometry(1000, 100, 50);//创建三维球

      materialOptions = {//材质
        color: new THREE.Color(0xffffff),
        size: 1.1,
        opacity: 0.8
      };

      starStuff = new THREE.PointsMaterial(materialOptions);


      for (var i = 0; i < amount; i++) {
        var item = new THREE.Vector3();
        item.x = Math.random() * 2000 - 1000;
        item.y = Math.random() * 2000 - 1000;
        item.z = Math.random() * 2000 - 1000;

        geometry.vertices.push(item);//放定点
      }

      stars = new THREE.Points(geometry, starStuff);
      scene.add(stars);
    }

    function onMouseMove(e) {
      mouseX = e.clientX - windowHalfX;
      mouseY = e.clientY - windowHalfY;
    }

  </script>
</body>

</html>